#include "crtmpmsgcreator.h"
#include "camf0stream.h"
#include "cmonitor.h"

#include <iostream>
using namespace std;


/////////////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS / DESTRUCTOR
/////////////////////////////////////////////////////////////////////////////////

CRtmpMsgCreator::CRtmpMsgCreator()
{
    m_iStreamID = 1.0;
}

CRtmpMsgCreator::~CRtmpMsgCreator()
{

}

/////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
/////////////////////////////////////////////////////////////////////////////////

CRtmpMessage CRtmpMsgCreator::ConnectReply()
{
    // create answer
    cout << endl << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    std::vector<std::pair<std::string,CAmf0Variant> > _object;

    _object.push_back(pair<std::string,CAmf0Variant>("description",CAmf0Variant(string("Connection succeeded."))));
    _object.push_back(pair<std::string,CAmf0Variant>("code",CAmf0Variant(string("NetConnection.Connect.Success"))));
    _object.push_back(pair<std::string,CAmf0Variant>("objectEncoding",CAmf0Variant(double(0))));
    _object.push_back(pair<std::string,CAmf0Variant>("details",CAmf0Variant(0,CAmf0Variant::AMF0_NULL)));
    _object.push_back(pair<std::string,CAmf0Variant>("level",CAmf0Variant(string("status"))));

    _amf0sout << CAmf0Variant(string("_result")) << CAmf0Variant(double(1)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL)
              << CAmf0Variant(_object,CAmf0Variant::AMF0_MIXED_ARRAY);
    cout << "Payload created" << endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::CreateStreamReply(int iTransID)
{
    // create answer
    cout << endl << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    _amf0sout << CAmf0Variant(string("_result")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL)
              << CAmf0Variant(double(m_iStreamID));
    m_iStreamID += 1;
    cout << "Payload created" <<  endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::AcceptReply(int iTransID)
{
    // create answer
    cout << endl << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    _amf0sout << CAmf0Variant(string("accepted")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL);
    cout << "Payload created" <<  endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::InviteReply()
{
    // create answer
    cout << endl << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    _amf0sout << CAmf0Variant(string("_result")) << CAmf0Variant(double(0)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL);
    cout << "Payload created" <<  endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::PublishReply(int iTransID)
{
    // create answer
    cout << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    std::vector<std::pair<std::string,CAmf0Variant> > _object;
    _object.push_back(pair<std::string,CAmf0Variant>("description",CAmf0Variant(string(""))));
    _object.push_back(pair<std::string,CAmf0Variant>("code",CAmf0Variant(string("NetStream.Publish.Start"))));
    _object.push_back(pair<std::string,CAmf0Variant>("details",CAmf0Variant(0,CAmf0Variant::AMF0_NULL)));
    _object.push_back(pair<std::string,CAmf0Variant>("level",CAmf0Variant(string("status"))));


    _amf0sout << CAmf0Variant(string("onStatus")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL)
              << CAmf0Variant(_object,CAmf0Variant::AMF0_MIXED_ARRAY);
    cout << "Payload created" << endl;

    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::PlayReply(int iTransID)
{
     // create answer
    cout << "Creating answer.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    std::vector<std::pair<std::string,CAmf0Variant> > _object;
    _object.push_back(pair<std::string,CAmf0Variant>("description",CAmf0Variant(string("remote"))));
    _object.push_back(pair<std::string,CAmf0Variant>("code",CAmf0Variant(string("NetStream.Play.Start"))));
    _object.push_back(pair<std::string,CAmf0Variant>("details",CAmf0Variant(0,CAmf0Variant::AMF0_NULL)));
    _object.push_back(pair<std::string,CAmf0Variant>("level",CAmf0Variant(string("status"))));


    _amf0sout << CAmf0Variant(string("onStatus")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL)
              << CAmf0Variant(_object,CAmf0Variant::AMF0_MIXED_ARRAY);
    cout << "Payload created" << endl;

    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}


CRtmpMessage CRtmpMsgCreator::StreamMessage(const std::string &stdPayload, int channel)
{
    return CreateMessage(20,CRtmpMessage::AUDIO_MESSAGE ,2 , stdPayload);
}


CRtmpMessage CRtmpMsgCreator::ByedRequest(int iTransID)
{
    // create answer
    cout << endl << "Creating request.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    _amf0sout << CAmf0Variant(string("byed")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL);
    cout << "Payload created" <<  endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}

CRtmpMessage CRtmpMsgCreator::RejectedRequest(int iTransID)
{
    // create answer
    cout << endl << "Creating request.." << endl;

    cout << "Creating payload." << endl;
    CAmf0StreamOut _amf0sout;
    _amf0sout << CAmf0Variant(string("rejected")) << CAmf0Variant(double(iTransID)) <<  CAmf0Variant(0,CAmf0Variant::AMF0_NULL)
              << CAmf0Variant(string("603 Decline"));
    cout << "Payload created" <<  endl;


    return CreateMessage(0,CRtmpMessage::AMF0_COMMAND_MESSAGE ,0 , _amf0sout.EncodeAmf());
}


/////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS
/////////////////////////////////////////////////////////////////////////////////

CRtmpMessage CRtmpMsgCreator::CreateMessage(int timestamp, CRtmpMessage::MsgType type,
                                            int streamId, const std::string &payload)
{
    cout << "Creating message." << endl;
    CRtmpMessage _message;
    _message.SetPayloadLen(payload.size());
    _message.SetTimestamp(timestamp);
    _message.SetSreamId(streamId);
    _message.SetMsgType(type);

    CMonitor::Draw(_message);
    cout << "Chunk header created." << endl;
    _message.PushToPayload(payload);

    //cout << "DecodeAmf: " << _amf0sout.DecodeAmf(_amf0sout.EncodeAmf().data(),_amf0sout.EncodeAmf().size()) << endl;
    cout << "Message complete." << endl << endl;

    return _message;
}

